var app_db='pbkb';                                                                                      // 创建新库/新应用时,第2步,修改此处(1/3)
// 定义一个全局变量,避免污染环境变量
var pbkb={
    system:'个人博客和团队知识库系统,欢迎您!'+'<a target="_blank" href="https://pbkb.houseschan.cn/?file_id=2&isdir=1">官方系统帮助</a> ',  // 系统欢迎语.创建新库/新应用时,第2步,修改此处(2/3),也可以不改
    title:'个人博客和团队知识库系统pbkb: Personal Blog and Knowledge Base - 开源改变世界,奉献比索取伟大',    // 首页的title.创建新库/新应用时,第2步,修改此处(3/3),也可以不改
    post_fail:'可能网络异常,也可能是网站故障,请稍后再试!',
    session_fail:'[fail] session会话超时或无效,请重新登录后,再进行操作!',
    user_id:0,
    admin:0,            // 用户是否group_id=1的管理组中的管理员
    username:'',
    session_id:'',
    file_id:1,
    isdir:1,
    pdir_id: 0,         // 文件的所在目录,在'新建文件'或'搜索文件'时有用
    path_id_chain: [1], // 文件路径的file_id链
    filenames: {
        '1': ''
    },
    filename:'',        // 当前文件名, 还原临时文件 时有用
    file_content:'',    // 当前文件内容, 还原临时文件 时有用
    font_size:'14px',           // 默认的字体大小
    font_family:'Courier New',  // 默认字体
    mkdir:0,            // 是否 新建目录 状态
    mkfile:0,           // 是否 新建文件 状态
    editfile:0,         // 是否 编辑文件 状态
    stype:'',           // 搜索类型,'非空'表示进入了搜索状态
    search:'',          // 用户输入的'搜索字符串',经过URI编码
    search_items:[]     // 搜索结果
    //hint:[]             // 弹出提示框的id
};
pbkb.timer_interval=2;                      // 编辑器每隔多少分钟保存一次临时文件
pbkb.$editor_body = '';                     // kindeditor的iframe中的body
//KindEditor.options.filterMode = false;    // 关闭editor的过滤模式
pbkb.editor_opts={
    uploadJson: app_db+'/editor_upload',
    allowFileManager: false,                // 插入'Flash/视频/文件'时,显示"文件空间"按钮;
    //fileManagerJson: 'pbkb/file_manager',
    //cssPath:'',                           // 指定编辑器的iframe使用哪些css文件,默认值为空,多个文件写在array中
    //urlType:'',                           // 改变站内URL.空为不修改URL,'relative'为相对路径,'absolute'为绝对路径,'domain'为带域名的绝对路
    //fontSizeTable:[],                     // 文件大小的列表,默认值:['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px']
    //filePostName:'imgFile',               // 上传文件的input的name属性的值
    extraFileUploadParams:{
        attached_tmp:pbkb.user_id+'_new'    // 上传文件的临时目录
    },
    cssData: 'body {font-family: '+pbkb.font_family+'; font-size:'+pbkb.font_size+'}', // 指定编辑器iframe document的CSS数据，用于设置可视化区域的样式。
    items:[
        'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',
        'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright',
        'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
        'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/',
        'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold',
        'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage',
        'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
        'anchor', 'link', 'unlink', '|', 'about'
    ],                                  // 因为不支持Flash和音频视频,所以取消了'flash'和'media'两个按钮
    //newlineTag:'br',                  // 换行符,默认值:'p'
    width: '100%'                       // 支持px和%
}
pbkb.editor_content={filename:'',content:''};  // 编辑文件时,编辑器的临时保存区


// 构成网页主体的4个部分
pbkb.$login=$('<div></div>');                               // part1
pbkb.$tip_login=$('<span></span>');

pbkb.$operation=$('<div style="display:inline"></div>');    // part2
//pbkb.$tip_operation=$('<span></span>');

pbkb.$path=$('<span id="span_path"></span>');               // part3,文件路径信息

pbkb.$main=$('<div style="clear:right"></div>');            // part4. clear属性:禁止右边出现浮动块(即pbkb.$main总出现在pbkb.$search的下方)
pbkb.$tip_main=$('<p></p>');


// 辅助函数,不改变环境变量
function time_tip(str){
    return hqc.get_date()+' '+str;
}
function is_empty(str) {
    var empty = /^ {0,}$/;
    return empty.test(str);
}
pbkb.$hint=$('<div id="hint" style="width: 100%;position: fixed;left: 0px;top: 0px;background: white;opacity:0.5;"></div>');    // opacity:默认值为1全不透明,0表示全透明
pbkb.$hint2=$('<div id="hint2" style="border:solid;background:white;position:fixed;text-align:center;"></div>');
function hint(str){
    hint_remove();
    pbkb.$hint.height($(window).height());
    $('body').append(pbkb.$hint);
    pbkb.$hint2.html(time_tip(str)+'<br/><button id="btn_hint" type="button" onclick="hint_remove()">知道了</button><br>快捷键: "Enter"或者"Esc"');
    $('body').append(pbkb.$hint2);
    pbkb.$hint2.css({top:(pbkb.$hint.height()/2-pbkb.$hint2.height()/2+'px'),left:pbkb.$hint.width()/2-pbkb.$hint2.width()/2+'px'});
    key_handler();
    //$('#hint').on('keydown',hint_shortcut());                 // div元素无法监听keydown事件
    //$(document).on('keydown',e=>{ console.log(e.target) });   // e.target保存着首先发生事件的元素,这行代码测得e.target===body,故此得知div无法监听keydown事件
}
function hint_shortcut(e){
    if (e.keyCode === 13 || e.keyCode === 27) {
        // 27 === Esc
        hint_remove();
    }
}
function hint_remove(){
    pbkb.$hint2.remove();
    pbkb.$hint.remove();
    key_handler();
}
function to_html_entity(s){       // 转换HTML实体，防范一些XSS攻击
    return s.replace(/(<)|(>)/g,function(match,p1,p2){
        if(p1) return '&lt;';
        if(p2) return '&gt;';
    });
}

// 与part1相关的函数,大多数函数用于辅助flush_login,在执行flush_login()之前负责改变环境变量
async function button_login() {
    if(is_empty($('#username').val())||is_empty($('#password').val())){
        alert('请输入 用户名 和 密码');
        return false;
    }
    pbkb.username=$('#username').val();
    hint('登录中,请稍候...');
    await login();
    if(pbkb.user_id>0){
        flush_all();
    }
}
async function login() {
    var login_data = {
        username: pbkb.username,
        user_id: pbkb.user_id,                                          // user_id不为0时,则是由cookie设置的,表示已登录
        session_id: pbkb.session_id,
        password: hqc.sha1( $('#password').val() ? $('#password').val() : 0 ),
    };
    await $.post(app_db+'/login', login_data, function(login_back) {    // $.post()的data是application/x-www-form-urlencoded格式,即username=abc&user_id=1&...
        pbkb.$tip_login.remove();
        if (login_back[0].user_id === 0) {
            pbkb.user_id = login_back[0].user_id;
            // pbkb.session_id!==''表示: cookies 设置了 session_id
            if(pbkb.session_id==='') hint('[fail] 登录失败: 用户名 或 密码 错误');
        } else if(login_back[0].user_id === -1){
            pbkb.user_id = login_back[0].user_id;
            hint('[fail] 禁止登录: 数据库配置错误,请检查 configuration 表');
        } else {
            hint_remove();
            pbkb.user_id = login_back[0].user_id;
            pbkb.username = login_back[0].username;
            pbkb.session_id = login_back[0].session_id;
            pbkb.editor_opts.extraFileUploadParams.attached_tmp=pbkb.user_id+'_new';
            pbkb.attached_path=login_back[0].attached_path;
            pbkb.attached_tmp=login_back[0].attached_tmp;
            pbkb.tmp_files=login_back[0].tmp_files;
            pbkb.admin=login_back[0].admin;
        }
    }).fail(()=>{
        hint('[fail] 登录失败: '+pbkb.post_fail);
    });
}
function button_logout(){
    // 设置环境变量
    if (pbkb.mkfile === 0 && pbkb.editfile === 0 && pbkb.mkdir ===0) {
        // 删除cookies
        $.post(app_db+'/del_cookie',{session_id:pbkb.session_id,user_id:pbkb.user_id});
        pbkb.user_id=0;
        pbkb.username='';
        pbkb.session_id='';
        pbkb.admin=0;
        pbkb.stype='';
        pbkb.search_items=[];
        if((pbkb.file_id=pbkb.path_id_chain.pop())===-1){
            pbkb.file_id=pbkb.path_id_chain.pop();
        }
        // 设置网页内容
        flush_all();
    } else {
        hint('您有文件正在编辑,请先取消编辑,再退出登录');
    }
}
function recover_tmp(){
    hint(' 正在为你还原尚未保存的文件...');
    $.post(app_db+'/recover_tmp',{user_id:pbkb.user_id,session_id:pbkb.session_id}).done(recover_tmp_back=>{
        if(recover_tmp_back.file_id===0){
            hint(pbkb.session_fail);
        }else{
            hint_remove();
            pbkb.tmp_files=0;
            if(recover_tmp_back.length===0){
                pbkb.$tip_login.remove();
                hint('没找到临时文件,可能已被另一个会话保存或删除了');
                return false;
            }
            pbkb.isdir=0;
            pbkb.filename=recover_tmp_back[0].filename;
            pbkb.file_content=recover_tmp_back[0].content;
            pbkb.recover=1;
            if(recover_tmp_back[0].file_id===0){
                // 新建文件
                pbkb.file_id=recover_tmp_back[0].pdir_id;
                pbkb.mkfile=1;
            } else {
                // 编辑文件
                pbkb.file_id=recover_tmp_back[0].file_id;
                pbkb.editfile=1;
            }
            flush_all();
        }
    }).fail(()=>{
        hint('[fail] 临时文件还原失败: '+pbkb.post_fail);
    });
}
function empty_search(){
    pbkb.search=$('#search').val();
    if(is_empty(pbkb.search)){
        alert('提示: 搜索内容不能为空');
        return false;
    }else{
        return true;
    }
}
function button_saf(){              // search_all_filename: 在所有目录中搜索文件名
    if(!empty_search()) return false;
    location.href='?search='+encodeURIComponent(pbkb.search)+'&stype=saf';
}
async function saf(){
    var post_data={search:to_html_entity(pbkb.search),user_id:pbkb.user_id,session_id:pbkb.session_id};
    await $.post(app_db+'/search_all_filename',post_data,f_list=>{
        pbkb.search_items=f_list;
    })
}
function button_sac(){              // search_all_content: 在所有目录中搜索文件的内容
    if(!empty_search()) return false;
    location.href='?search='+encodeURIComponent(pbkb.search)+'&stype=sac';
}
async function sac(){               // search_all_content: 在所有目录中搜索文档内容
    var post_data={search:to_html_entity(pbkb.search),user_id:pbkb.user_id,session_id:pbkb.session_id};
    await $.post(app_db+'/search_all_content',post_data,f_list=>{
        pbkb.search_items=f_list;
    });
}
function button_scf(){              // search_cur_filename: 在当前目录中搜索文件名
    if(!empty_search()) return false;
    if(pbkb.path_id_chain.pop()===-1){
        //在搜索结果中再次搜索
        location.href='?search='+encodeURIComponent(pbkb.search)+'&stype=scf&file_id='+pbkb.pdir_id;
    }else{
        location.href='?search='+encodeURIComponent(pbkb.search)+'&stype=scf&file_id='+pbkb.file_id;
    }
}
async function scf(){               // search_cur_filename: 在当前目录中搜索文件名
    //var post_data={search:pbkb.search,file_id:(pbkb.stype===''?pbkb.file_id:pbkb.file_id)};
    var post_data={search:to_html_entity(pbkb.search),file_id:pbkb.file_id,user_id:pbkb.user_id,session_id:pbkb.session_id};
    await $.post(app_db+'/search_cur_filename',post_data,f_list=>{
        pbkb.search_items=f_list;
    });
}
function button_scc(){              // search_cur_content: 在当前目录中搜索匹配的文档内容
    if(!empty_search()) return false;
    if(pbkb.path_id_chain.pop()===-1){
        //在搜索结果中再次搜索
        location.href='?search='+encodeURIComponent(pbkb.search)+'&stype=scc&file_id='+pbkb.pdir_id;
    }else{
        location.href='?search='+encodeURIComponent(pbkb.search)+'&stype=scc&file_id='+pbkb.file_id;
    }
}
async function scc(){
    //var post_data={search:pbkb.search,file_id:(pbkb.stype!==''?pbkb.file_id:pbkb.file_id)};
    var post_data={search:to_html_entity(pbkb.search),file_id:pbkb.file_id,user_id:pbkb.user_id,session_id:pbkb.session_id};
    await $.post(app_db+'/search_cur_content',post_data,f_list=>{
        pbkb.search_items=f_list;
    });
}
function user_m(){
    var $user_m=$('<div id="user_m" style="width: 100%;position: fixed;left: 0px;top: 0px;background: white;opacity:0.5;"></div>');
    // opacity: 0全透明,1全不透明
    $user_m.height($(window).height());
    var $user_m2=$('<div id="user_m2" style="border: solid;background:white;position:fixed;">'+
        '<p>用户管理:</p>'+
        '用户名:<input type="text" id="username" placeholder="请输入用户名"/> '+
        '<button type="button" onclick="useradd()">新增</button> '+
        '<button type="button" onclick="userdel()">删除</button> '+
        '<button type="button" onclick="change_username()">改名</button> '+
        '<button type="button" onclick="userquery()">查询用户ID</button> '+
        '<a target="_blank" href="'+app_db+'/usersinfo?uid='+pbkb.user_id+'&sid='+pbkb.session_id+'">列出用户信息</a><br>'+
        '&nbsp;&nbsp;密码:<input type="password" id="password" /> '+
        '<button type="button" onclick="password_reset()">重置密码</button>'+
        '<p>组管理:</p>'+
        '&nbsp;&nbsp;组名:<input type="text" id="groupname" placeholder="请输入组名"/> '+
        '<button type="button" onclick="groupadd()">新增</button> '+
        '<button type="button" onclick="groupdel()">删除</button> '+
        '<button type="button" onclick="change_groupname()">改名</button> '+
        '<button type="button" onclick="groupquery()">查询组ID</button> '+
        '<a target="_blank" href="'+app_db+'/groupsinfo?uid='+pbkb.user_id+'&sid='+pbkb.session_id+'">列出组信息</a><br>'+
        '用户ID:<input type="text" id="group_uid" placeholder="加入组或从组中删除时,须输入用户ID"/> '+
        '<button type="button" onclick="group_add_mem()">加入组中</button> '+
        '<button type="button" onclick="group_del_mem()">从组中删除</button>'+
        '<p style="text-align:center;"><button type="button" id="user_m_close" onclick="user_m_close()">关闭</button> 快捷键: Esc</p></div>');
    $('body').append($user_m);
    $('body').append($user_m2);
    $user_m2.css({top:($user_m.height()/2-$user_m2.height()/2+'px'),left:$user_m.width()/2-$user_m2.width()/2+'px'});
    key_handler();
}
function user_m_close(){
    $('#user_m2').remove();
    $('#user_m').remove();
    key_handler();
}
function user_m_shortcut(e){
    //if (e.keyCode === 13 || e.keyCode === 27) {
    if (e.keyCode === 27) {     // Enter快捷键不生效(因为div里面含有input元素的缘故?)
        // 27 === Esc
        user_m_close();
    }
}
function useradd(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        username:$('#username').val(),
        password:$('#password').val()
    }
    if(is_empty(data.username)){
        alert('新增用户时,须输入用户名~');
        return false;
    }
    if(is_empty(data.password)){
        alert('新增用户时,须输入密码~');
        return false;
    }
    data.password=hqc.sha1(data.password);
    $.post(app_db+'/useradd',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 创建用户失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 创建用户失败: 用户名已存在');
        }else{
            alert('[ OK ] 成功创建用户: '+data.username);
        }
    }).fail(()=>{
        alert('[fail] 创建用户失败: '+pbkb.post_fail);
    });
}
function userdel(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        username:$('#username').val()
    }
    if(is_empty(data.username)){
        alert('删除用户时,须输入用户名~');
        return false;
    }
    $.post(app_db+'/userdel',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 删除用户失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 删除用户失败: 用户名不存在');
        }else if(back[0].status===4){
            alert('[fail] 删除用户失败: 不准删除系统保留用户');
        }else{
            alert('[ OK ] 成功删除用户: '+data.username);
        }
    }).fail(()=>{
        alert('[fail] 删除用户失败: '+pbkb.post_fail);
    });
}
function change_username(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        username:$('#username').val()
    }
    if(is_empty(data.username)){
        alert('修改用户名时,须输入用户名~');
        return false;
    }
    // 提示改为什么名字？
    data.new_name = prompt('请输入新的用户名: ', data.username); // 当用户按下“取消”时，new_name的值为null
    if( data.new_name===null || is_empty(data.new_name) || data.new_name===data.username){
        alert('您没有输入新的用户名,或取消了操作,或用户名保持不变.');
        return false;
    }
    $.post(app_db+'/change_username',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 修改用户名失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 修改用户名失败: 原用户名不存在,或新用户名已存在');
        }else if(back[0].status===4){
            alert('[info] 新用户名与原用户名相同');
        }else{
            alert(`[ OK ] 用户名修改成功: "${data.username}" 修改为 "${data.new_name}"`);
        }
    }).fail(()=>{
        alert('[fail] 修改用户名失败: '+pbkb.post_fail);
    });
}
function userquery(){
    var data={
        username:$('#username').val()
    }
    if( is_empty(data.username) ){
        alert('查询用户ID时,须输入用户名~');
        return false;
    }
    $.post(app_db+'/userquery',data).done(back=>{
        if(back.length){
            alert('"'+data.username+'" 的用户ID是: '+back[0].user_id);
        }else{
            alert('[fail] 查询失败: 用户不存在');
        }
    }).fail(()=>{
        alert('[fail] 查询失败: '+pbkb.post_fail);
    });
}
function password_reset(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        username:$('#username').val(),
        password:$('#password').val()
    }
    if(is_empty(data.username)){
        alert('重置密码时,须输入用户名~');
        return false;
    }
    if(is_empty(data.password)){
        alert('重置密码时,须输入密码~');
        return false;
    }
    data.password=hqc.sha1(data.password);
    $.post(app_db+'/password_reset',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 重置密码失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 重置密码失败: 用户名不存在');
        }else{
            alert('[ OK ] 已为 "'+data.username+'" 重置密码');
        }
    }).fail(()=>{
        alert('[fail] 重置密码失败: '+pbkb.post_fail);
    });
}
function groupadd(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        groupname:$('#groupname').val()
    }
    if(is_empty(data.groupname)){
        alert('新增组时,须输入组名~');
        return false;
    }
    $.post(app_db+'/groupadd',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 新增组失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 新增组失败: 组名已存在');
        }else{
            alert('[ OK ] 成功创建组: '+data.groupname);
        }
    }).fail(()=>{
        alert('[fail] 创建组失败: '+pbkb.post_fail);
    });
}
function groupdel(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        groupname:$('#groupname').val()
    }
    if(is_empty(data.groupname)){
        alert('删除组时,须输入组名~');
        return false;
    }
    // 管理组和普通组不能删除
    $.post(app_db+'/groupdel',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 删除组失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 删除组失败: 组名不存在');
        }else if(back[0].status===4){
            alert('[fail] 删除组失败: 不准删除系统保留组');
        }else{
            alert('[ OK ] 成功删除了组: '+data.groupname);
        }
    }).fail(()=>{
        alert('[fail] 删除组失败: '+pbkb.post_fail);
    });
}
function change_groupname(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        groupname:$('#groupname').val()
    }
    if(is_empty(data.groupname)){
        alert('修改组名时,须输入组名~');
        return false;
    }
    data.new_name = prompt('请输入新的组名: ', data.groupname);
    if(data.new_name===null || is_empty(data.new_name) || data.new_name===data.groupname){
        alert('您没有输入新的组名,或取消了操作,或组名保持不变.');
        return false;
    }
    $.post(app_db+'/change_groupname',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 修改组名失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 修改组名失败: 原组名不存在,或新组名已存在');
        }else if(back[0].status===4){
            alert('[info] 新组名与原组名相同');
        }else{
            alert(`[ OK ] 组名修改成功: "${data.groupname}" 修改为 "${data.new_name}"`);
        }
    }).fail(()=>{
        alert('[fail] 修改组名失败: '+pbkb.post_fail);
    });
}
function groupquery(){
    var data={
        groupname:$('#groupname').val()
    }
    if(is_empty(data.groupname)){
        alert('查询组ID时,须输入组名~');
        return false;
    }
    $.post(app_db+'/groupquery',data).done(back=>{
        if(back.length){
            alert('"'+data.groupname+'" 的组ID是: '+back[0].group_id);
        }else{
            alert('[fail] 查询失败: 您输入了不存在的组名');
        }
    }).fail(()=>{
        alert('[fail] 查询失败: '+pbkb.post_fail);
    });
}
function group_add_mem(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        groupname:$('#groupname').val(),
        group_uid:$('#group_uid').val()
    }
    if(is_empty(data.groupname)){
        alert('新增组成员时,须输入组名~');
        return false;
    }
    if(is_empty(data.group_uid)){
        alert('新增组成员时,须输入用户ID~');
        return false;
    }
    $.post(app_db+'/group_add_mem',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 新增组成员失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 新增组成员失败: 组名或组员不存在');
        }else if(back[0].status===4){
            alert('[fail] 新增组成员失败: 不要往 group_id=0 的组加入新成员');
        }else if(back[0].status===5){
            alert('[info] user "'+back[0].username+'" 已经是 "'+data.groupname+'" 的组内成员');
        }else{
            alert('[ OK ] 成功把user "'+back[0].username+'" 加入到组: '+data.groupname);
        }
    }).fail(()=>{
        alert('[fail] 新增组成员失败: '+pbkb.post_fail);
    });
}
function group_del_mem(){
    var data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        groupname:$('#groupname').val(),
        group_uid:$('#group_uid').val()
    }
    if(is_empty(data.groupname)){
        alert('删除组成员时,须输入组名~');
        return false;
    }
    if(is_empty(data.group_uid)){
        alert('删除组成员时,须输入用户ID~');
        return false;
    }
    $.post(app_db+'/group_del_mem',data).done(back=>{
        if(back[0].status===1 || back[0].status===2){
            alert('[fail] 删除组成员失败: 你是非法用户');
        }else if(back[0].status===3){
            alert('[fail] 删除组成员失败: 组名或组员不存在');
        }else if(back[0].status===4){
            alert('[fail] 删除组成员失败: 不要往 group_id=0 的组删除成员,也不要往 group_id=1 的组删除 user_id=1 的成员');
        }else if(back[0].status===5){
            alert('[info] user "'+back[0].username+'" 并不是 "'+data.groupname+'" 的组内成员');
        }else{
            alert('[ OK ] 成功把user "'+back[0].username+'" 从组 "'+data.groupname+'" 中删除');
        }
    }).fail(()=>{
        alert('[fail] 新增组成员失败: '+pbkb.post_fail);
    });
}

// part2,协助flush_operation,负责改变环境变量的函数
function button_mkdir(){
    pbkb.mkdir=1;
    pbkb.isdir=0;
    flush_all();
}
function button_mkfile(){
    pbkb.mkfile=1;
    pbkb.isdir=0;
    flush_all();
}
function button_editfile(){
    var post_data={
        user_id:pbkb.user_id,
        session_id:pbkb.session_id,
        file_id:pbkb.file_id
    }
    $.post(app_db+'/button_editfile',post_data).done(back=>{
        if(back[0].status===1){
            hint(pbkb.session_fail);
        }else if(back[0].status===2){
            hint('[fail] 不能编辑文件: 因为你不是作者,也不是组成员');
        }else{
            pbkb.editfile=1;
            flush_all();
        }
    }).fail(()=>{
        hint('[fail] 不能编辑文件: '+pbkb.post_fail);
    });
}
function button_mkdir_ok(){
    if (is_empty($('#filename').val())) {
        hint('<b>注意: 文件名不能为空</b>');
        return false;
    }
    hint('正在创建目录,请稍候...');
    pbkb.mkdir=0;
    var mkdir_data = {
        filename: to_html_entity($('#filename').val()),       // 此处要防范存储型XSS攻击
        pdir_id: pbkb.pdir_id,
        user_id: pbkb.user_id,
        session_id: pbkb.session_id
    };
    $.post(app_db+'/mkdir', mkdir_data, (mkdir_back) => {
        if (mkdir_back[0].status === 1) {
            hint(pbkb.session_fail);
        } else if(mkdir_back[0].status === 2){
            hint('[fail] 不准创建目录: 你不是管理员,也不是组成员.');
        } else {
            hint_remove();
            get_pfiles();
        };
    }).fail(()=>{
        hint('[fail] 不能创建目录: '+pbkb.post_fail);
    });
}
function button_mkdir_cancel(){
    if (confirm('你确定不创建新目录吗?')) {
        pbkb.mkdir=0;
        if(pbkb.top){
            pbkb.top=0;
            flush_all();
        }else{
            get_pfiles();
        }
    }
}
function button_mkfile_ok() {
    if (is_empty($('#filename').val())) {
        hint('<b>注意: 文件名不能为空</b>');
        return false;
    }
    hint('正在保存文件,请稍候...');
    pbkb.mkfile=0;
    clearInterval(pbkb.timer);
    var mkfile_pre_data={
        pdir_id: pbkb.pdir_id,
        user_id: pbkb.user_id,
        session_id: pbkb.session_id
    }
    $.post(app_db+'/mkfile_pre', mkfile_pre_data, (mkfile_pre_back)=>{  // mkfile_pre为了获取file_id和btime
        if(mkfile_pre_back[0].status===1){
            hint(pbkb.session_fail);
        } else if(mkfile_pre_back[0].status===2){
            hint('[fail] 不准创建文件: 你不是管理员,也不是组成员.');
        } else {
            var ymd=new Date(mkfile_pre_back[0].btime * 1000);          // year month day
            var year=ymd.getFullYear()+'';
            var mon=ymd.getMonth()>8 ? (ymd.getMonth()+1)+'' : '0' + (ymd.getMonth()+1);
            var day=ymd.getDate()>9 ? ymd.getDate()+'' : '0' + ymd.getDate();
            // r_new=/(files_tmp\/1_new/)(\d{13,}_.*?)(")/g
            var r_new=new RegExp('('+pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp+'/)(\\d{13,}_.*?)(")','g');  // 问号是非贪婪的最短匹配
            // r_new匹配超链接(上传图片时不须匹配正文),r_news匹配超链接和正文(上传文件时应匹配正文)
            var r_news=new RegExp('('+pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp+'/)(\\d{13,}_.*?)(["<])','g');
            var a=[];
            var content_tmp=pbkb.editor.html();
            pbkb.attachments_new=[];                                    // 若不清空,再次创建文件时就会出错
            while( (a=r_new.exec(content_tmp)) !== null ){
                pbkb.attachments_new.push(a[2]);
            }
            var mkfile_data = {
                user_id: pbkb.user_id,
                session_id: pbkb.session_id,
                file_id: mkfile_pre_back[0].file_id,
                filename: to_html_entity($('#filename').val()),         // 此处要防范存储型XSS攻击
                pdir_id: pbkb.pdir_id,
                btime: mkfile_pre_back[0].btime,
                content: content_tmp.replace(r_news,pbkb.attached_path+'/'+year+'/'+mon+day+'/'+mkfile_pre_back[0].file_id+'/$2$3')
                    .replace(/(<h\d.*?>)\s*(\S.*?)\s*(<\/h\d>)/g,'$1$2$3')      // 删除<h\d>后面的空白格\s,删除</h\d>前面的空白格,非空白格是\S
                    .replace(/(<h\d.*?)(\sid=["']\s{0,}["'])(.*?>.*?<\/h\d>)/g,'$1$3'),     // 删除id=''或id="".手写的代码通常不会出现这些错误,而复制其他网站的代码时就可能出错
                text: pbkb.editor.text().replace(r_news,pbkb.attached_path+'/'+year+'/'+mon+day+'/'+mkfile_pre_back[0].file_id+'/$2$3')
                    .replace(/<img .*?\/>/g,''),                                // 删除img标签,因为.text()方法不删除img标签
                year: year,
                monthday: mon+day,
                attached_tmp_uid: pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp,
                attachments_new: JSON.stringify(pbkb.attachments_new)           // $.post()的application/x-www-form-urlencoded格式不适合传递数组
            };
            $.post(app_db+'/mkfile', mkfile_data, (mkfile_back) => {
                if (mkfile_back[0].status === 1) {
                    hint(pbkb.session_fail)
                }if(mkfile_back[0].status === 2){
                    hint('[fail] 不准创建文件: 你不是管理员,也不是组成员.');
                }else{
                    var url=window.location.href;
                    location.href=url.replace(/\?.*|#.*/,'')+'?file_id='+mkfile_pre_back[0].file_id+'&isdir=0';
                    /*
                    hint_remove();
                    pbkb.file_id=mkfile_pre_back[0].file_id;
                    flush_all();
                    */
                }
            });
        }
    }).fail(()=>{
        hint('[fail] 不能保存文件: '+pbkb.post_fail);
    });
}
function button_mkfile_cancel(){
    if (confirm('你确定不创建新文件吗?')) {
        pbkb.$tip_main.html(time_tip('正在删除临时文件,请稍候...'));
        pbkb.$main.prepend(pbkb.$tip_main);
        pbkb.mkfile=0;
        clearInterval(pbkb.timer);
        var cancel_data = {
            user_id: pbkb.user_id,
            session_id:pbkb.session_id,
            attached_tmp_uid: pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp
        };
        $.post(app_db+'/del_editor_content', cancel_data);
        if(pbkb.top){
            pbkb.top=0;
            flush_all();
        }else{
            get_pfiles();
        }
    }
}
function button_editor_higher(){
    $('textarea.ke-edit-textarea').height($('textarea.ke-edit-textarea').height()+50);
    $('iframe').height($('iframe').height()+50);
    $('div.ke-edit').height($('div.ke-edit').height()+50);
    //$('div.ke-container').height($('div.ke-container').height()+50);      // div.ke-container会自动调节
}
function button_editor_lower(){
    $('textarea.ke-edit-textarea').height($('textarea.ke-edit-textarea').height()-50);
    $('iframe').height($('iframe').height()-50);
    $('div.ke-edit').height($('div.ke-edit').height()-50);
    //$('div.ke-container').height($('div.ke-container').height()-50);      // 若同时调节div.ke-container,反而使div.ke-statusbar显示异常
}
function button_editfile_ok() {                         // BUG: 若同一个user同时编辑同一个文件,则前面提交的人可能把图片都删除了,而后面提交的人无从得知
    if (is_empty($('#filename').val())) {
        hint('<b>注意: 文件名不能为空</b>');
        return false;
    }
    pbkb.$tip_main.html(time_tip('正在保存文件,请稍候...'));
    pbkb.$main.prepend(pbkb.$tip_main);
    pbkb.editfile=0;
    clearInterval(pbkb.timer);
    var editfile_pre_data={
        user_id: pbkb.user_id,
        session_id: pbkb.session_id,
        file_id: pbkb.file_id
    }
    $.post(app_db+'/editfile_pre', editfile_pre_data, (editfile_pre_back)=>{  // editfile_pre为了获取文件的btime
        if(editfile_pre_back[0].status===1){
            hint(pbkb.session_fail);
        } else if(editfile_pre_back[0].status===2){
            hint('[fail] 不能编辑: 文件可能已被删除')
        } else {
            var ymd=new Date(editfile_pre_back[0].btime * 1000);            // year month day
            var year=ymd.getFullYear()+'';
            var mon=ymd.getMonth()>8 ? (ymd.getMonth()+1)+'' : '0' + (ymd.getMonth()+1);
            var day=ymd.getDate()>9 ? ymd.getDate()+'' : '0' + ymd.getDate();
            var r_new=new RegExp('('+pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp+'/)(\\d{13,}_.*?)(")','g');
            var r_old=new RegExp(['(',pbkb.attached_path,'/',year,'/',mon,day,'/',pbkb.file_id,'/)(\\d{13,}_.*?)(")'].join(''),'g');
            var r_news=new RegExp('('+pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp+'/)(\\d{13,}_.*?)(["<])','g');
            var a=[];
            var content_tmp=pbkb.editor.html();
            pbkb.attachments_new=[];                                        // 若不清空,再次创建文件时就会出错
            pbkb.attachments_old=[];
            while( (a=r_new.exec(content_tmp)) !== null ){
                pbkb.attachments_new.push(a[2]);
            }
            while( (a=r_old.exec(content_tmp)) !== null ){
                pbkb.attachments_old.push(a[2]);
            }
            var editfile_data = {
                user_id: pbkb.user_id,
                session_id: pbkb.session_id,
                filename: $('#filename').val(),
                file_id: pbkb.file_id,
                content: content_tmp.replace(r_news,pbkb.attached_path+'/'+year+'/'+mon+day+'/'+pbkb.file_id+'/$2$3')
                    .replace(/(<h\d.*?>)\s*(\S.*?)\s*(<\/h\d>)/g,'$1$2$3')      // 删除<h\d>后面的空白格,删除</h\d>前面的空白格,该步骤便于后面flush_headers()函数的实现
                    .replace(/(<h\d.*?)(\sid=["']\s{0,}["'])(.*?>.*?<\/h\d>)/g,'$1$3'),     // 删除id=''或id="".手写的代码通常不会出现这些错误,而复制其他网站的代码时就可能出错
                text: pbkb.editor.text().replace(r_news,pbkb.attached_path+'/'+year+'/'+mon+day+'/'+pbkb.file_id+'/$2$3')
                    .replace(/<img .*?\/>/g,''),                                // 删除img标签,因为.text()方法不删除img标签
                year: year,
                monthday: mon+day,
                attached_tmp_uid: pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp,
                attachments_new: JSON.stringify(pbkb.attachments_new),          // $.post()的application/x-www-form-urlencoded格式不适合传递数组
                attachments_old: JSON.stringify(pbkb.attachments_old)
            };
            $.post(app_db+'/editfile', editfile_data, (editfile_back) => {
                if (editfile_back[0].status === 1) {
                    hint(pbkb.session_fail);
                }else if(editfile_back[0].status === 2){
                    hint('[fail] 不能编辑: 因为你不是作者,也不是组成员')
                }else{
                    get_cfiles(pbkb.file_id,0);
                }
            });
        }
    }).fail(()=>{
        hint('[fail] 不能保存文件: '+pbkb.post_fail);
    });
}
function button_editfile_cancel() {
    if (confirm('你确定取消编辑吗?')) {
        pbkb.$tip_main.html(time_tip('正在删除临时文件,请稍候...'));
        pbkb.$main.prepend(pbkb.$tip_main);
        pbkb.editfile=0;
        clearInterval(pbkb.timer);
        var cancel_data = {
            user_id: pbkb.user_id,
            session_id:pbkb.session_id,
            attached_tmp_uid: pbkb.attached_tmp+'/'+pbkb.editor_opts.extraFileUploadParams.attached_tmp
        };
        $.post(app_db+'/del_editor_content', cancel_data)
        if(pbkb.top){
            pbkb.top=0;
            flush_all();
        }else{
            get_cfiles(pbkb.file_id,0);
        }
    }
}
function button_delfile() {                             // 浏览文件内容时的"删除文件"按钮
    if (confirm('是否要删除本文件?')) {
        hint('正在删除文件,请稍候...');
        var delete_data = {
            user_id: pbkb.user_id,
            session_id: pbkb.session_id,
            file_id: pbkb.file_id
        };
        $.post(app_db+'/button_delfile', delete_data, (back) => {
            if (back[0].status===0 || back[0].status===2) {
                // 文件已被删除,或成功删除时
                hint_remove();
                get_pfiles();
            } else if(back[0].status===3){
                hint('[fail] 不能删除文件: 因为你不是作者,也不是组成员');
            } else {
                hint(pbkb.session_fail);
            }
        }).fail(()=>{
            hint('[fail] 不能删除文件: '+pbkb.post_fail);
        });
    };
}

// part3,协助flush_path,负责改变环境变量的函数
function set_fileID_pdirID(isdir) {
    if (pbkb.path_id_chain.length > 1) {
        var cur_file = pbkb.path_id_chain.length - 1;
        var pdir = pbkb.path_id_chain.length - 2;

        pbkb.file_id = pbkb.path_id_chain[cur_file];
        pbkb.isdir = isdir;
        pbkb.pdir_id = pbkb.path_id_chain[pdir];
    } else {
        pbkb.file_id = 1;
        pbkb.isdir = 1;
        pbkb.pdir_id = 0;
    }
}

// part4,主要协助flush_main,负责改变环境变量的函数
function button_pdir() {                    // 上级目录
    if (pbkb.file_id === 1) {
        hint('<b>已是顶层目录</b>');
    } else {
        if (pbkb.mkfile === 0 && pbkb.editfile === 0 && pbkb.mkdir ===0) {
            get_pfiles();
        } else {
            if(pbkb.mkdir ===1) button_mkdir_cancel();
            if(pbkb.mkfile ===1) button_mkfile_cancel();
            if(pbkb.editfile ===1) button_editfile_cancel();
        }
    }
}
function top_button(){
    top_set_env();
}
function top_set_env(){
    if (pbkb.file_id === 1) {
        hint('<b>已是顶层目录</b>');
    } else {
        /*
        pbkb.file_id=1;
        pbkb.isdir=1;
        pbkb.top=1;
        // 在搜索状态时想要回到顶层目录,就要退出搜索状态
        if(pbkb.stype){
            pbkb.stype='';
            pbkb.search_items=[];
        }
        */
        if(pbkb.mkdir===0 && pbkb.mkfile===0 && pbkb.editfile===0){
            /*
            pbkb.top=0;
            flush_all();
            */
            location.href='?file_id=1&isdir=1';
        }else{
            if(pbkb.mkdir ===1) button_mkdir_cancel();
            if(pbkb.mkfile ===1) button_mkfile_cancel();
            if(pbkb.editfile ===1) button_editfile_cancel();
        }
    }
}
function get_pfiles() {                     // pfile: parent files,获取上级目录的文件
    pbkb.path_id_chain.pop();
    set_fileID_pdirID(1);
    /*
    pbkb.stype='';
    pbkb.search_items=[];
    flush_all();
    */
    location.href='?file_id='+pbkb.file_id+'&isdir=1';
}
function get_cfiles(file_id, isdir) {       // cfile: child file
    /*
    pbkb.file_id=file_id;
    pbkb.isdir=isdir;
    flush_all();
    */
   location.href='?file_id='+file_id+'&isdir='+isdir;
}
function create_editor(){
    /*
    await $.getScript('../kindeditor/kindeditor.js').done(()=>{
        $.getScript('../kindeditor/lang/zh_CN.js');
    }).fail(()=>{
        hint('[fail] 不能创建编辑器: '+pbkb.post_fail)
        return false;
    })
    */
    pbkb.editor_opts.height=($(window).height()-231-pbkb.$path.height())+'px';
    // 231 = login:28  <hr>:16  filename:21  确认或取消编辑:51  工具栏:55  正文的padding:10  状态栏:17  结尾提示:33
    pbkb.editor = KindEditor.create('#pbkb_editor', pbkb.editor_opts);
    // 若内容有变化,保存临时文件
    pbkb.timer = setInterval(save_editor_content, pbkb.timer_interval * 60 * 1000, pbkb.file_id, pbkb.user_id, pbkb.session_id);
    pbkb.$editor_body = $($("iframe")[0].contentWindow.document.body);              // pbkb.$editor_body用于设置“提交”快捷键。注意：获取iframe的内容时，须同源。
    // 获取跨域访问的iframe内容时,会报错: Uncaught DOMException: Blocked a frame with origin "https://pbkb.houseschan.cn" from accessing a cross-origin frame.
    //pbkb.$editor_body.css({fontSize:pbkb.font_size,fontFamily:pbkb.font_family});
}
function save_editor_content(file_id, user_id, session_id) {
    var filename = $('#filename').val(),
        content = pbkb.editor.html();
    if (pbkb.editor_content.filename !== filename || pbkb.editor_content.content !== content) {
        pbkb.editor_content.filename = filename;
        pbkb.editor_content.content = content;
        var save_data = {
            user_id: user_id,
            session_id: session_id,
            filename: filename,
            file_id: file_id,
            pdir_id: pbkb.pdir_id,
            content: content
        };
        $.post(app_db+'/save_editor_content', save_data, (back) => {
            if (back[0].status === 1) {
                clearInterval(pbkb.timer);
                hint(pbkb.session_fail);
            } else {
                pbkb.$tip_main.html(time_tip('[OK] 临时文件保存成功'));
                pbkb.$main.append(pbkb.$tip_main);
            }
        })
    }
}



// 网页入口
// $.post(...).done(data=>{alert(data)}).fail(callback_function).always(callback_function); $.post()/$.ajax()/$.get()等都返回一个jqXHR对象,jqXHR对象是promise对象
// $.post()默认的Content-Type: application/x-www-form-urlencoded; charset=UTF-8
// 而且 post_data={file_id:1} 也会被转化为 file_id=1 这样的字符串,而不是json对象
// 若 response 是 text/json,则jquery将 response data 解析为对象
// 若 response 是 text/html,则jquery将 response data 解析为字符串
async function cookie_handler(){              // cookie只有:user_id和session_id
    await $.post(app_db+'/check_cookie').done(function(check_cookie_back){
        if(check_cookie_back[0].user_id>0){
            // 已登录
            pbkb.user_id=check_cookie_back[0].user_id;
            pbkb.session_id=check_cookie_back[0].session_id;
            pbkb.username=check_cookie_back[0].username;
            //await login();                  // 不知为何.done()的异步回调函数中的await无效
        }
    });
    if(pbkb.user_id) await login();
}
async function querystring_handler(){         // 处理三种querystring: file_id, isdir, search
    // file_id不存在时,getUrlParameter('file_id')返回null,而Number(null)则返回0
    if(Number(hqc.getUrlParameter('file_id'))===0){
        // 没有file_id参数时
        pbkb.file_id=1;
    } else {
        pbkb.file_id=Number(hqc.getUrlParameter('file_id'));
    }
    
    if(hqc.getUrlParameter('isdir')===null){
        // 没有isdir参数时
        pbkb.isdir=1;
    } else {
        pbkb.isdir=Number(hqc.getUrlParameter('isdir'));
    }
    
    if(pbkb.user_id>0){
        // 登录后的用户才允许搜索
        if(hqc.getUrlParameter('search')===null){
            pbkb.search='';
        } else {
            pbkb.search=hqc.getUrlParameter('search',1);
            switch(hqc.getUrlParameter('stype')){
                case 'saf':         // search all filename
                    pbkb.stype='saf';
                    await saf();
                    break;
                case 'sac':         // search all content
                    pbkb.stype='sac';
                    await sac();
                    break;
                case 'scf':         // search current filename
                    pbkb.stype='scf';
                    await scf();
                    break;
                case 'scc':         // search current content
                    pbkb.stype='scc';
                    await scc();
                    break;
                default:
                    pbkb.stype='';
            }
        }
    }
}

async function flush_all(a){        // a 是个数组,如[1,2,3] [2,3,4]
    if(a){
        var i;
        for(i in a){
            switch (a[i]){
                case 1:
                    flush_login();
                    break;
                case 2:
                    flush_operation();
                    break;
                case 3:
                    await flush_path();
                    break;
                case 4:
                    await flush_main();
                    break;
                default:
                    ;
            }
        }
    } else {
        flush_login();      // part1;
        flush_operation();  // part2;
        await flush_path(); // part3;
        await flush_main(); // part4;
    }
    key_handler();          // 元素出现之前不能绑定快捷键,故key_handler()只能在最后处理
}


function flush_login(){     // part1
    pbkb.$login.empty();
    if(pbkb.user_id>0){
        // 已登录
        if(pbkb.admin){
            pbkb.$login.html(pbkb.system+'已登录,用户名: '+pbkb.username+' <button type="button" onclick="button_logout()">退出登录</button> '+
            '<button type="button" onclick="user_m()">用户(组)管理</button>');
        }else{
            pbkb.$login.html(pbkb.system+'已登录,用户名: '+pbkb.username+' <button type="button" onclick="button_logout()">退出登录</button>');
        }
        if(pbkb.mkdir===0 && pbkb.mkfile===0 && pbkb.editfile===0 && pbkb.isdir===1){
            // float元素的默认width:auto,效果不好
            pbkb.$login.append('<div style="float: right; width:745px"><input id="search" '+
            'placeholder="输入搜索内容.英文字符不区分大小写,可以使用通配符:下划线匹配单个字符,百分号匹配0个或多个字符" type="text" style="width:100%"/><br/>'+
            '<button type="button" onclick="button_saf()">搜索<b class="red">所有目录</b>中的文件名Enter</button> '+
            '<button type="button" onclick="button_sac()">搜索<b class="red">所有目录</b>中的内容Ctrl+Enter</button> '+
            '<button type="button" onclick="button_scf()">搜索<b class="blue">当前目录</b>中的文件名</button> '+
            '<button type="button" onclick="button_scc()">搜索<b class="blue">当前目录</b>中的内容</button></div>');
        }
        // 上次有尚未保存的文件
        if(pbkb.tmp_files){
            pbkb.$tip_login.html(' 您有尚未保存的临时文件,您可以:<button type="button" onclick="recover_tmp()">恢复文件/继续编辑</button>');
            pbkb.$login.append(pbkb.$tip_login);
        }
    } else {
        // 未登录
        pbkb.$login.html(pbkb.system+'username:<input type="text" id="username" /> ' +
        'password:<input type="password" id="password" /> ' +
        '<button type="button" onclick="button_login()">登录</button> 快捷键:Enter');
    }
}



function flush_operation(){ // part2
    pbkb.$operation.empty();
    pbkb.$operation.append('<button type="button" onclick="top_button()">顶层目录</button><button type="button" onclick="button_pdir()" style="margin-left: 7px">上级目录</button>');
    if(pbkb.user_id>0){
        if(pbkb.isdir){
            //打开目录时
            //if( !pbkb.stype && pbkb.mkdir===0 && pbkb.mkfile===0 ){
            if( pbkb.search_items.length===0 && pbkb.mkdir===0 && pbkb.mkfile===0 ){
                //不在搜索状态时
                pbkb.$operation.append('<button type="button" onclick="button_mkdir()" style="margin-left: 7px">创建目录</button>');
                //pbkb.$operation.append('<button type="button" onclick="button_mkfile()">创建文件</button>').css({marginLeft:'7px'});
                pbkb.$operation.append('<button type="button" onclick="button_mkfile()" style="margin-left: 7px">创建文件</button>');
            }
        }else{
            //打开文件时,不可能处于搜索状态
            if(pbkb.mkdir===0 && pbkb.mkfile===0 && pbkb.editfile===0){
                pbkb.$operation.append('<button type="button" onclick="button_editfile()" style="margin-left: 7px">修改文件名或内容</button>');
                pbkb.$operation.append('<button type="button" onclick="button_delfile()" style="margin-left: 7px">删除文件</button>');
            }
        }
    }
}


async function flush_path(){      // part3
    pbkb.$path.empty();
    if(pbkb.file_id===1){
        pbkb.path_id_chain=[1];
    }else{
        // 获取 pbkb.path_id_chain 和 pbkb.filenames
        await $.post(app_db+'/get_full_path',{file_id:pbkb.file_id},(rows)=>{
            pbkb.path_id_chain=JSON.parse(rows[0].path_id_chain);
            pbkb.filenames=JSON.parse(rows[0].filenames);
        });
    }
    if(pbkb.mkdir || pbkb.mkfile){
        pbkb.path_id_chain.push(0);
        pbkb.filenames['0']='[[正在创建新文件...]]';
    }
    if(pbkb.search_items.length){
        pbkb.path_id_chain.push(-1);
        switch(pbkb.stype){
            case 'saf':
                pbkb.filenames['-1']='[[saf: "'+to_html_entity(pbkb.search)+'"]]';  // 转换实体以防范映射型XSS攻击
                break;
            case 'sac':
                pbkb.filenames['-1']='[[sac: "'+to_html_entity(pbkb.search)+'"]]';
                break;
            case 'scf':
                pbkb.filenames['-1']='[[scf: "'+to_html_entity(pbkb.search)+'"]]';
                break;
            case 'scc':
                pbkb.filenames['-1']='[[scc: "'+to_html_entity(pbkb.search)+'"]]';
                break;
            default:
                pbkb.filenames['-1']='[[error for: "'+to_html_entity(pbkb.search)+'"]]';
        }
    }
    set_fileID_pdirID(pbkb.isdir);      // part4执行get_files时,依赖pbkb.isdir和pbkb.file_id的值,因此part4要等待part3执行完毕
    
    var path = ' [当前节点信息] {file_id: '+pbkb.file_id+', full path: ';
    for (var i in pbkb.path_id_chain) {
        path += '/' + pbkb.filenames[pbkb.path_id_chain[i] + ''];
    }
    path=path.replace(/(\/)(\/.*$)/,'$2');
    pbkb.$path.html(path+'}');
    
    var last_node=pbkb.path_id_chain[pbkb.path_id_chain.length-1]
    if(last_node===-1){
        document.title=app_db+': 搜索结果';
    }else if(last_node===0){
        document.title=app_db+': 新建文件中...';
    }else if(last_node===1){
        document.title=pbkb.title;
    }else{
        if(pbkb.editfile){
            document.title='edit: '+pbkb.filenames[String(pbkb.file_id)];
        }else{
            document.title=app_db+': '+pbkb.filenames[String(pbkb.file_id)];
        }
    }
    pbkb.$path.append('<hr/>');
}



async function flush_main(){      // part4
    pbkb.$main.empty();
    if(pbkb.search_items.length===0 && pbkb.mkfile===0 && pbkb.editfile===0 && pbkb.mkdir===0){
        await get_files(pbkb.file_id,pbkb.isdir);
        if(pbkb.stype){
            $('#search').val(pbkb.search);
            hint('没有匹配的搜索结果,搜索的内容是: <b>'+to_html_entity(pbkb.search)+'</b>');    // 此处要防范映射型XSS攻击
            pbkb.stype='';
        }
    }
    if(pbkb.search_items.length){
        pbkb.$table.empty();
        pbkb.$main.append(pbkb.$table);
        pbkb.$table.append(pbkb.$search_table_header);
        $('#search').val(pbkb.search);
        // 列出搜索结果...
        var i;
        for (var i in pbkb.search_items) {
            $('<tr><td>' + pbkb.search_items[i].file_id + '</td>' +                         // file_id===0时,可能是黑客在测试session_id
            '<td>' + (pbkb.search_items[i].file_id===0?pbkb.session_fail:
'<a target="_blank" href="?file_id='+pbkb.search_items[i].file_id+'&isdir='+pbkb.search_items[i].isdir+'">'+pbkb.search_items[i].filename+'</a>') + '</td>' +   // 文件名
            '<td>' + (pbkb.search_items[i].file_id===0?'NULL':pbkb.search_items[i].username) + '</td>' +               // 作者
            '<td>' + (pbkb.search_items[i].file_id===0?'NULL':(pbkb.search_items[i].isdir?pbkb.search_items[i].groupname:'无')) + '</td>' +      // 组名,普通文件没有组名
            '<td>' + (pbkb.search_items[i].file_id===0?'无权限':
'<a href="?file_id='+pbkb.search_items[i].file_id+'&isdir='+pbkb.search_items[i].isdir+'">'+(pbkb.search_items[i].isdir?'浏览目录':'打开文件')+'</a>')+'</td>'+
            '<td>' + (pbkb.search_items[i].file_id===0?'无权限':hqc.get_date(pbkb.search_items[i].mtime)) + '</td>'+    // 上次修改时间
            '<td><a target="_blank" href="?file_id='+pbkb.search_items[i].pfile_id+'&isdir=1">'+pbkb.search_items[i].pfilename+'</a></td>'+     // 上级目录
            '<td>结果'+(Number(i)+1)+'</td></tr>')                                          // '操作'
            .appendTo(pbkb.$table);
        }
    }
    if(pbkb.mkdir===1){
        pbkb.$main.append('<input id="filename" type="text" placeholder="请输入目录名" style="width: 100%;font-size:'+pbkb.font_size+';font-family:'+pbkb.font_family+'"/>'+
        '<p><button type="button" onclick="button_mkdir_ok()">确认创建目录</button> 快捷键:Enter <button type="button" onclick="button_mkdir_cancel()">取消创建目录</button></p>');
        $('#filename').focus();
    }
    if(pbkb.mkfile===1){
        pbkb.$main.append('<input id="filename" type="text" placeholder="请输入文件名" style="width: 100%;font-size:'+pbkb.font_size+';font-family:'+pbkb.font_family+'"/>'+
        '<p><button type="button" onclick="button_mkfile_ok()">确认创建文件</button> 快捷键:Ctrl+Enter'+
        ' <button type="button" onclick="button_mkfile_cancel()">取消创建文件</button>'+
        ' <button type="button" onclick="button_editor_higher()">增加编辑框高度</button>'+
        ' <button type="button" onclick="button_editor_lower()">减少编辑框高度</button></p>'+
        '<textarea id="pbkb_editor"></textarea>');          // textarea不能用jQuery对象代替,会出错的.
        create_editor();
        //$('#filename').focus();
        if(pbkb.recover){
            pbkb.recover=0;
            $('#filename').val(pbkb.filename);
            pbkb.editor.html(pbkb.file_content);
        }
    }
    if(pbkb.editfile===1){          // 此处会遗留一个BUG,若多人同时编辑同一个文件,则以最后编辑的那个为准.建议多人同时编辑时,弹出提示,是否覆盖
        await $.post(app_db+'/get_files', {file_id:pbkb.file_id,isdir:pbkb.isdir,user_id: pbkb.user_id,session_id: pbkb.session_id}, function(f_data){
            if(f_data==='0'){
                pbkb.editfile=0;
                hint('[fail] 获取文件内容失败: 文件已被删除,或您输入的参数有误');
                return false;       // 不执行以后可能出现的key_handler()
            } else {
                pbkb.$main.append('<input id="filename" type="text" value="" style="width: 100%;font-size:'+pbkb.font_size+';font-family:'+pbkb.font_family+'"/>'+
                '<p><button type="button" onclick="button_editfile_ok()">确认编辑文件</button> 快捷键:Ctrl+Enter'+
                ' <button type="button" onclick="button_editfile_cancel()">取消编辑文件</button>'+
                ' <button type="button" onclick="button_editor_higher()">增加编辑框高度</button>'+
                ' <button type="button" onclick="button_editor_lower()">减少编辑框高度</button></p>'+
                '<textarea id="pbkb_editor"></textarea>');
                //$('#pbkb_editor').val(pbkb.file_content);           // 有时要用.html(),有时要用.val(),好神奇啊...
                create_editor();
                if(pbkb.recover){
                    pbkb.recover=0;
                    $('#filename').val(pbkb.filename);
                    pbkb.editor.html(pbkb.file_content);
                    pbkb.editor_content.filename=pbkb.filename;
                    pbkb.editor_content.content=pbkb.file_content;
                }else{
                    var last_file_id = pbkb.path_id_chain[pbkb.path_id_chain.length - 1] + '';
                    $('#filename').val(pbkb.filenames[last_file_id]);
                    pbkb.editor.html(f_data[0].content);
                    pbkb.editor_content.filename=pbkb.filenames[last_file_id];
                    pbkb.editor_content.content=f_data[0].content;
                }
                //$('#filename').focus();
            }
        }).fail(()=>{
            pbkb.editfile=0;
            hint('[fail] 获取文件内容失败: '+pbkb.post_fail);
            return false;       // 不执行以后可能出现的key_handler()
        });
    }
}
pbkb.$table = $('<table id="table_files" border="1"></table>');
pbkb.$search_table_header = $('<tr><th>file_id</th><th>文件名</th><th>作者</th><th>组名</th><th>目录or文件</th><th>上次修改时间</th><th>上级目录</th><th>操作</th></tr>');
pbkb.$files_table_header = $('<tr><th>file_id</th><th>文件名</th><th>作者</th><th>组名</th><th>目录or文件</th><th>上次修改时间</th><th>操作</th></tr>');
async function get_files(file_id, isdir) {
    var post_data = {
        file_id:file_id,
        isdir:isdir,
        user_id: pbkb.user_id,
        session_id: pbkb.session_id
    };
    pbkb.$tip_main.empty();
    pbkb.$main.append(pbkb.$tip_main);
    hint('正在获取文件内容,请稍候...');
    await $.post(app_db+'/get_files', post_data, function(f_list) {
        if(f_list==='0'){
            hint('[fail] 获取文件内容失败: 目录已被删除,或您输入的参数有误');
            return false;
        }
        if(isdir){
            // 如果是目录,获取该目录的file_list
            hint_remove();
            pbkb.$table.empty();
            pbkb.$main.append(pbkb.$table);
            pbkb.$table.append(pbkb.$files_table_header);
            for (var i in f_list) {
                if( ! f_list[i].hidden || (f_list[i].hidden && f_list[i].user_id===pbkb.user_id)){      // 文件创建者,可以显示隐藏的文件清单
                    $('<tr><td>' + f_list[i].file_id + '</td>' +                                                   // file_id
                        '<td>' + (f_list[i].file_id?'<a target="_blank" href="?file_id='+f_list[i].file_id+'&isdir='+f_list[i].isdir+'">'+f_list[i].filename+'</a>':'当前目录无文件') + '</td>' +                 // 文件名
                        '<td>' + (f_list[i].file_id?f_list[i].username:'null') + '</td>' +                          // 作者
                        '<td>' + (f_list[i].file_id?(f_list[i].isdir?f_list[i].groupname:'无'):'null') + '</td>' +   // 组名,普通文件没有组名
                        '<td>' + (f_list[i].file_id?
                                    (f_list[i].isdir?
                                        '<button type="button" onclick="get_cfiles(' + f_list[i].file_id + ',' + f_list[i].isdir + ')">进入目录</button>' :
                                        //'<a href="?file_id='+f_list[i].file_id+'&isdir='+f_list[i].isdir+'" id="a'+f_list[i].file_id+'">打开文件</a>' // a元素的id用于绑定click事件
                                        '<a href="?file_id='+f_list[i].file_id+'&isdir='+f_list[i].isdir+'">打开文件</a>'
                                    ):'当前目录无文件'
                                 )+'</td>'+
                        
                        '<td>' + (f_list[i].file_id?hqc.get_date(f_list[i].mtime):'null') + '</td>' +   // mtime
                        (pbkb.user_id === 0?'<td>未登录</td>':                                           // 操作,前端决定显示哪些按钮,后端做安全检查检查,决定能否执行某个操作
                            (f_list[i].file_id === 0 ?'<td>无文件</td>':
                                '<td>'+
                                '<button type="button" onclick="del_cfile(' + f_list[i].file_id + ',' + f_list[i].isdir + ',' + pbkb.file_id + ')">删除</button> ' +
                                '<button type="button" onclick="movedir(' + f_list[i].file_id + ')">移动</button> ' +
                                '<button type="button" onclick="re_name(' + f_list[i].file_id + ')">改名</button> ' +
                                '<button type="button" onclick="toggle_pri('+f_list[i].file_id+','+f_list[i].hidden+')">'+(f_list[i].hidden?'显示文件':'隐藏文件')+'</button> '+    // 隐藏文件,即设为私有,仅自己可访问;显示文件,即设为公共文件,所有人可访问
                                '<button type="button" onclick="toggle_top('+f_list[i].file_id+','+f_list[i].istop+')">'+(f_list[i].istop?'取消置顶':'置顶')+'</button> '+
                                (f_list[i].owner?'<button type="button" onclick="change_group('+f_list[i].file_id+')">修改组</button> ':'')+'</td>'))+
                    '</tr>')
                    .appendTo(pbkb.$table);
                }
                /*
                if(f_list[i].file_id !== 0 && f_list[i].isdir === 0){
                    $('#a'+f_list[i].file_id).on('click',e=>{
                        e.preventDefault();
                        //get_cfiles(f_list[i].file_id,f_list[i].isdir);                    // 发生click事件时的i的值是固定的
                        get_cfiles(Number($(e.target).attr('id').replace(/^a/,'')),0);
                    })
                }
                */
            }
        }else{
            hint_remove();
            pbkb.$main.html(f_list[0].content);
            // 增加 标题导航的div
            flush_headers();
        }
    }).fail(()=>{
        hint('[fail] 获取文件内容失败: '+pbkb.post_fail);
    });
}
pbkb.$navi=$('<div id="navi" class="right" style="border: thin dashed;background-color: rgba(255,255,255,0.5);overflow:auto"></div>');    // navigation:导航
pbkb.$navi_body=$('<p id="navi_body"></p>');
function flush_headers(){
    pbkb.$navi_body.empty();
    //pbkb.$navi.removeattr('style');    // 删除所有CSS样式
    pbkb.$navi.empty();
    pbkb.$navi.css('height','');     // 仅删除某个CSS属性
    pbkb.$navi.css('width','');
    var sub_replace=function(match,p1,p2,p3){
        return p1+p2.replace(/<.*?>/g,'')+p3;                   // 删除多余的HTML标签
    }
    var id_replace=function(match,p1,p2,p3){
        if(/ id=["']/.test(p1)){
            // 若header中原本就有id属性,就什么都不做
            return match;
        } else {
            // 若header中没有id属性,就加上id属性
            var id=p2.replace(/<.*?>/g,'');                     // 当出现多个同名的标题时,只能跳转到前面的标题,不会跳到后面的标题
            return p1+' id="'+id+'">'+p2+'</h'+p3+'>';
        }
    }
    var gen_space=function(n){
        var i=0, spaces='';
        for(i;i<n;i++){
            spaces+='&nbsp;';
        }
        return spaces;
    }
    pbkb.$navi_body.append('<p>'+pbkb.filenames[String(pbkb.file_id)]+'</p>');
    var str=pbkb.$main.html().replace(/(<h\d.*?>.*?)(<.*?>.*?)(<\/h\d>)/g,sub_replace);
    var a=[];
    var r_header=/<h(\d)(.*?)>(.*?)<\/h\d>/g;
    while ((a=r_header.exec(str))!==null){
        if(/ id=["']/.test(a[2])){
            // 若header中原本就有id属性
            var id_value=/ id="(.*?)"| id='(.*?)'/.exec(a[2]);
            // 第1个括号是id_value[1],第2个括号是id_value[2];其实不需要id_value[2],因为kindeditor会将单引号转换为双引号
            if(id_value[1]){
                // id_value[1] 匹配时
                pbkb.$navi_body.append('<a href="#'+id_value[1]+'">'+gen_space(Number(a[1])*2)+id_value[1]+'</a><br/>');
            } else {
                // id_value[2] 匹配时
                pbkb.$navi_body.append('<a href="#'+id_value[2]+'">'+gen_space(Number(a[1])*2)+id_value[2]+'</a><br/>');
            }
        } else {
            // 若header中没有id属性
            pbkb.$navi_body.append('<a href="#'+a[3]+'">'+gen_space(Number(a[1])*2)+a[3]+'</a><br/>');
        }
    }
    // 修改pbkb.$main的内容
    pbkb.$main.html(pbkb.$main.html().replace(/(<h\d.*?)>(.*?)<\/h(\d)>/g,id_replace));
    // 增加 $navi
    pbkb.$navi.append('<b>标题导航</b> <a href="#">top</a> <button type="button" onclick="toggle_headers()">隐藏/显示标题栏</button>');
    pbkb.$navi.append(pbkb.$navi_body);
    pbkb.$main.prepend(pbkb.$navi);
    // 限制 导航栏 的宽度 和 高度
    pbkb.navi={};
    if(pbkb.$navi.width()+50 > $(window).width()/2){
        pbkb.$navi.width($(window).width()/2);
    }else{
        pbkb.$navi.width(pbkb.$navi.width()+50);    // +50 可以使 top 和 button 显示在同一行("上下滚动条"可能大概占了50个像素吧?并不需要考虑"左右滚动条",因为文字会自动换行)
    }
    pbkb.navi.width=pbkb.$navi.width();             // 不会显示水平滚动条,因为会自动换行
    
    var navi_h=pbkb.$navi.height(),
        win_h=$(window).height(),
        part1_h=pbkb.$login.height(),
        part2_h=pbkb.$operation.height(),
        part3_h=pbkb.$path.height();                // part3的高度第一次打开时是正确的,刷新时就不正确了...我觉得是Chrome的BUG
    if(navi_h > win_h - part1_h - part2_h - part3_h){   // 需要显示滚动条
        pbkb.$navi.height(win_h - part1_h - part2_h - part3_h - 50);    // 若不减50,布局会出问题
    }/*else{                                            // 不需要显示滚动条,就不需要设置div的高度了
        pbkb.$navi.height(pbkb.$navi.height());         // 必须设置 div 的高度，才能显示滚动条
    }*/
    pbkb.navi.height=pbkb.$navi.height();
}
function toggle_headers(){
    if(pbkb.$navi_body[0].isConnected){
        pbkb.$navi_body.remove();
        pbkb.$navi.css('height','');     // 仅删除某个CSS属性
        pbkb.$navi.css('width','');
    }else{
        pbkb.$navi.append(pbkb.$navi_body);
        pbkb.$navi.width(pbkb.navi.width);
        pbkb.$navi.height(pbkb.navi.height);
    }
}
function del_cfile(file_id, isdir, pdir_id) {       // 目录文件列表中的'删除'按钮
    $.post(app_db+'/get_filename',{file_id:file_id}).done(data=>{
        if(data.length===0){
            hint('[fail] 文件可能已被删除')
        }else{
            if (confirm(`是否要删除文件: {${data[0].filename}}`)) {
                hint('正在删除文件,请稍候...');
                var delete_data = {
                    user_id: pbkb.user_id,
                    session_id: pbkb.session_id,
                    file_id: file_id
                };
                $.post(app_db+'/del_cfile', delete_data, async (back) => {
                    if (back[0].status === 1) {
                        hint(pbkb.session_fail);
                    } else if (back[0].status === 2) {
                        hint('[fail] 不能删除非空目录: {' + back[0].filename+'}');
                    } else if(back[0].status === 3){
                        hint('[fail] 不能删除文件: {' + back[0].filename+'}, 文件可能已被删除');
                    } else if(back[0].status === 4){
                        hint('[fail] 不能删除文件: {' + back[0].filename+'}, 因为你不是作者,也不是组成员');
                    } else {
                        // 删除成功
                        //hint_remove();
                        await get_files(pbkb.file_id, pbkb.isdir);
                        //pbkb.$tip_main.html(time_tip('[OK] 成功删除了' + (isdir === 1 ? '空目录: {' : '文件: {') + back[0].filename+'}'));
                        hint('[OK] 成功删除了' + (isdir === 1 ? '空目录: ' : '文件: ') + '{'+back[0].filename+'}');
                    }
                });
            }
        }
    }).fail(()=>{
        hint('[fail] 文件删除失败: '+pbkb.post_fail);
    });
}
function movedir(file_id) {
    var target_id = Number(prompt(`[请确认] 是否要移动 file_id: ${file_id}? 请输入目标目录的 file_id: `, 0));   // Number()会将null转换为0,将字符串转为NaN,而NaN==NaN返回false
    if (!(target_id > 0)) {
        hint('您输入了错误的file_id,或取消了操作');
        return false;
    }
    hint('目录移动中,请稍候...');
    $.post(app_db+'/get_full_path',{file_id:file_id},from_back=>{
        var movedir_data = {
            user_id: pbkb.user_id,
            session_id: pbkb.session_id,
            from: file_id,
            to: target_id
        };
        $.post(app_db+'/movedir', movedir_data, (movedir_back) => {
            if (movedir_back[0].status === 1) {
                hint(pbkb.session_fail);
            } else if (movedir_back[0].status === 2) {
                hint('[fail] <b>移动失败: 您输入了系统中不存在的file_id或该file_id不是目录</b>');
            } else if(movedir_back[0].status === 3){
                hint('[fail] <b>移动失败: 源文件不存在,可能已被删除</b>');
            } else if(movedir_back[0].status === 4){
                hint('[fail] <b>移动失败: 因为你不是目标目录的作者,也不是组成员</b>');
            } else if(movedir_back[0].status === 5){
                hint('[fail] <b>移动失败: 因为你不是源文件的作者,也不是组成员</b>');
            } else {
                $.post(app_db+'/get_full_path',{file_id:target_id},to_back=>{
                    get_files(pbkb.file_id, pbkb.isdir);
                    var from_path_id_chain=JSON.parse(from_back[0].path_id_chain);
                    var to_path_id_chain=JSON.parse(to_back[0].path_id_chain);
                    var from_filenames=JSON.parse(from_back[0].filenames);
                    var to_filenames=JSON.parse(to_back[0].filenames);
                    var from_full_path='', to_full_path='', node;
                    while( (node=from_path_id_chain.pop()) > 1 ){
                        from_full_path=from_filenames[node+'']+'/'+from_full_path;
                    }
                    from_full_path=from_full_path.replace(/^(.*)\/$/,'/$1');
                    while( (node=to_path_id_chain.pop()) > 1 ){
                        to_full_path=to_filenames[node+'']+'/'+to_full_path;
                    }
                    if((to_full_path=to_full_path.replace(/^(.*)\/$/,'/$1'))===''){
                        to_full_path='/';   // 移至根目录时,会出现to_full_path=''的情况
                    };
                    hint(`[OK] 成功把 {${from_full_path}} 移至 {${to_full_path}} 中`);
                })
            }
        }).fail(()=>{
            hint('[fail] 目录移动失败: '+pbkb.post_fail);
        });
    })
};
function re_name(file_id){                  // rename在数据库中是保留字,故用re_name
    $.post(app_db+'/get_filename',{file_id:file_id}).done(data=>{
        if(data.length===0){
            hint('[fail] 不能改名: 文件可能已被删除')
        }else{
            var new_name = prompt(`若需修改 file_id: ${file_id} 的文件名,请输入新名字: `, data[0].filename); // 当用户按下“取消”时，new_name的值为null
            if(new_name===null || is_empty(new_name) || new_name===data[0].filename){
                hint('您没有输入新名字,或取消了操作,文件名保持不变.');
                return false;
            }
            hint('正在重命名,请稍候...');
            var rename_data = {
                user_id: pbkb.user_id,
                session_id: pbkb.session_id,
                file_id: file_id,
                name: new_name
            };
            $.post(app_db+'/re_name', rename_data, (rename_back) => {
                if (rename_back[0].status === 1) {
                    hint(pbkb.session_fail);
                } else if(rename_back[0].status === 2){
                    hint('[fail] 不能改名: 文件可能已被删除');      // 这一判断基本不会被执行,因为上面的程序已经判断了文件是否存在
                } else if (rename_back[0].status === 3){
                    hint('[fail] 不能重命名: 因为你不是作者,也不是组成员');
                } else {
                    pbkb.filenames[file_id+'']=new_name;
                    get_files(pbkb.file_id, pbkb.isdir);
                    hint(`[OK] 成功把 file_id: ${file_id} 重命名为: {${new_name}}`);
                }
            }).fail(()=>{
                hint('[fail] 重命名失败: '+pbkb.post_fail);
            });
        }
    });
}
function toggle_top(file_id, istop) {
    hint('置顶切换中,请稍候...');
    var top_data = {
        user_id: pbkb.user_id,
        session_id: pbkb.session_id,
        file_id: file_id,
        istop: istop
    };
    $.post(app_db+'/toggle_top', top_data, (back) => {
        if (back[0].status === 1) {
            hint(pbkb.session_fail);
        } else if (back[0].status === 2){
            hint('[fail] 置顶操作失败: 因为你不是管理员');
        } else {
            hint_remove();
            get_files(pbkb.file_id, pbkb.isdir);
        }
    }).fail(()=>{
        hint('[fail] 置顶操作失败: '+pbkb.post_fail);
    });
}
function toggle_pri(file_id, hidden) {
    hint('文件隐私切换中,请稍候...');
    var pri_data = {
        user_id: pbkb.user_id,
        session_id: pbkb.session_id,
        file_id: file_id,
        hidden: hidden
    };
    $.post(app_db+'/toggle_pri', pri_data, (back) => {
        if (back[0].status === 1) {
            hint(pbkb.session_fail);
        } else if (back[0].status === 2){
            hint('[fail] 操作失败: 因为你不是文件的作者');
        } else {
            hint_remove();
            get_files(pbkb.file_id, pbkb.isdir);
        }
    }).fail(()=>{
        hint('[fail] 置顶操作失败: '+pbkb.post_fail);
    });
}
function change_group(file_id){
    var $change_group=$('<div id="change_group" style="width: 100%;position: fixed;left: 0px;top: 0px;background: white;opacity:0.5;"></div>');
    // opacity: 0全透明,1全不透明
    $change_group.height($(window).height());
    var $change_group2=$('<div id="change_group2" style="border: solid;background: white;position:fixed;text-align:center;"></div>');
    $.get(app_db+'/get_groups').done(back=>{
        for(var i in back){
            $change_group2.append('<input type="radio" name="group_id" value="'+back[i].group_id+'" /> '+back[i].group_id+' '+back[i].groupname+(back[i].group_id?'':' 所有人都可以读写')+'<br>');
        }
        // 增加"确定"和"取消"按钮
        $change_group2.append('<button type="button" onclick="change_group_OK('+file_id+')">确定修改</button>"Enter" ');
        $change_group2.append('<button type="button" id="chgrp_cancel" onclick="change_group_CANCEL()">取消修改</button>"Esc"');
        $('body').append($change_group);
        $('body').append($change_group2);
        $change_group2.css({top:($change_group.height()/2-$change_group2.height()/2+'px'),left:$change_group.width()/2-$change_group2.width()/2+'px'});
        key_handler(file_id);
        // 设置默认组
        $.post(app_db+'/get_group_id',{file_id:file_id}).done(group_id=>{
            $('input[value='+group_id[0].group_id+']').attr('checked','true');
        });
    }).fail(()=>{
        hint('[fail] 不能"修改组": '+pbkb.post_fail);
    });
}
function change_group_CANCEL(){
    $('#change_group2').remove();
    $('#change_group').remove();
    key_handler();
}
function change_group_OK(file_id){
    var group_data={
        group_id:$('input:radio:checked').val(),
        user_id: pbkb.user_id,
        session_id: pbkb.session_id,
        file_id: file_id
    }
    $.post(app_db+'/change_group_OK',group_data).done(back=>{
        if(back[0].status===1){
            hint(pbkb.session_fail);
        }else if(back[0].status===2){
            // 不是owner,不准更新
            hint('[fail] 不能"修改组": 你不是管理员,也不是创建者.');
        }else{
            // 修改成功,刷新main
            change_group_CANCEL();
            flush_all([4]);
        }
    }).fail(()=>{
        hint('[fail] 不能"修改组": '+pbkb.post_fail);
    });
}

/* keydown keyup keypress常用属性,注意大小写
 * e.altKey = false;
 * e.ctrlKey = true;
 * e.shiftKey = false;
 * e.key = 'Enter';
 * e.keyCode = 13;
 */
function key_handler(file_id){                  // 目前只有change_group()中的key_handler()需要传入file_id
    /*
    var document_event=$._data(document,'events');
    if(!(document_event && document_event['keydown'])){
        // 未绑定'登录快捷键',则绑定
        $(document).on('keydown', shortcut_login);
    }
    */
    $(document).off('keydown');
    if(pbkb.$hint[0].isConnected){              // hint弹出框提示存在时,屏蔽其他快捷键
        $(document).on('keydown',hint_shortcut);
    } else {
        if($('#change_group2').length){         // 修改组时,屏蔽其他快捷键
            $(document).on('keydown',change_group_shortcut(file_id));
        }else{
            if($('#user_m2').length){           // 用户(组)管理时,屏蔽其他快捷键
                $(document).on('keydown',user_m_shortcut);
            }else{
                if(pbkb.user_id>0 && pbkb.isdir){   // pbkb.mkdir===1 && pbkb.mkfile===1 && pbkb.editfile===1时,pbkb.isdir===0
                    // 存在搜索框时
                    $(document).on('keydown', shortcut_search);
                }else{
                    if(pbkb.user_id===0) $(document).on('keydown', shortcut_login);
                    if(pbkb.mkdir===1) $(document).on('keydown', shortcut_mkdir);
                    if(pbkb.mkfile===1){
                        $(document).on('keydown', shortcut_mkfile);
                        pbkb.$editor_body.on('keydown', shortcut_mkfile);
                    }
                    if(pbkb.editfile===1){
                        $(document).on('keydown', shortcut_editfile);
                        pbkb.$editor_body.on('keydown', shortcut_editfile);
                    }
                }
            }
        }
    }
    focus_handler();
}
function shortcut_login(e) {
    if (e.keyCode === 13) {
        button_login();
    }
}
function shortcut_mkdir(e) {
    if (e.keyCode === 13) {
        button_mkdir_ok();
    }
}
function shortcut_mkfile(e) {
    if (e.ctrlKey === true && e.keyCode === 13) {
        button_mkfile_ok();
    }
}
function shortcut_editfile(e) {
    if (e.ctrlKey === true && e.keyCode === 13) {
        button_editfile_ok();
    }
}
function shortcut_search(e){
    if (e.keyCode === 13) {
        if (e.ctrlKey === true){
            button_sac();
        } else {
            button_saf();
        }
    }
}
function change_group_shortcut(file_id){
    return function(e){
        if (e.keyCode === 13) {
            change_group_OK(file_id);
        }
        if (e.keyCode === 27) {
            change_group_CANCEL();
        }
    }
}
function focus_handler(){
    if(pbkb.$hint[0].isConnected){
        // hint弹出框提示存在时,让hint button获得焦点
        $('#btn_hint').focus();
    } else {
        if($('#change_group2').length){         // 修改组时,"取消修改"获得焦点
            $('#chgrp_cancel').focus();
        }else{
            if($('#user_m2').length){           // 用户(组)管理时,“关闭按钮”获得焦点
                $('#user_m_close').focus();
            }else{
                if(pbkb.user_id===0){   // 未登录
                    $('#username').focus();
                }else{                  // 已登录
                    if(pbkb.mkdir || pbkb.mkfile || pbkb.editfile){
                        $('#filename').focus();
                    }else{
                        $('#search').focus();
                    }
                }
            }
        }
    }
}
